from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyKDE4.plasma import Plasma
from PyKDE4.kdeui import *
from PyKDE4.kdecore import *

import os

from actions import *

def local_icon(name):
    return KIcon(os.path.dirname(__file__) + "/icons/" + name + ".png")

class SeekAmountController(QObject):
    '''Object that maintains incremental seek amounts.'''

    def __init__(self):
        self.enabled = False
        self.seek_times = [(3,1), (3,2), (3,3), (3,4), (8,5), (10,10), (10,20), (-1, 30)]

        self.timer = QTimer()
        self.connect(self.timer, SIGNAL("timeout()"), self.increase)
        self.reset()

    def increase(self):
        "Increase the seem amount. Normally triggered by an internal timeout"
        self.index += 1
        if self.index >= len(self.seek_times):
            self.index = len(self.seek_times)-1
        (interval, self.seek_amount) = self.seek_times[self.index]
        if interval > 0:
            self.timer.setInterval(interval * 1000)
        else:
            self.stop()
    
    def reset(self):
        "Reset the seek amount to the first increment"
        self.index = -1
        self.increase()

    def start(self):
        "Reset the seek amount and start the internal timer"
        self.enabled = True
        self.reset()
        self.timer.start()

    def stop(self):
        "Stop the internal timer and disable increasing"
        self.timer.stop()
        self.enabled = False

    def pause(self):
        "Stop the internal timer temporarily"
        if self.timer.isActive():
            self.timer.stop()

    def resume(self):
        '''Restart the internal timer after it has been paused. 
        If the controller is disabled, then this will do nothing'''
        if self.enabled and not self.timer.isActive():
            self.timer.start()

    def amount(self):
        "Return the current seek amount"
        return self.seek_amount



class SeekController(QObject):
    "This object is used to seek in in the MPD server"
    def __init__(self, button=None, client=None, direction=1, threshold=1000, interval=150, click=None):
        '''Create a new SeekController. 

        Parameter button must a Qt object implementing the isUnderMouse method and have signals pressed and clicked
        Parameter client must implement the seek method
        Parameter direction is the seek direction (1 or -1)
        Parameter threshold is the number of milliseconds before seeking starts
        Parameter interval is how often seeking takes place
        Parameter click is a function to call if the user clicks before the threshold is reached
        '''

        self.button = button
        self.threshold = threshold
        self.interval = interval
        self.client = client
        self.direction = direction
        self.click_cb = click

        self.is_repeating = False
        self.amount_controller = SeekAmountController()

        self.timer = QTimer()
        self.connect(self.timer, SIGNAL("timeout()"), self.timeout)

        if self.button:
            self.connect(self.button, SIGNAL("pressed(bool)"), self.press)
            self.connect(self.button, SIGNAL("clicked()"), self.click)

    def timeout(self):
        "Called when the internal timer runs out"
        if not self.is_repeating:
            self.timer.setInterval(self.interval)
            self.amount_controller.start()
            self.is_repeating = True

        if self.button.isUnderMouse():
            self.amount_controller.resume()
            self.seek(self.amount_controller.amount() * self.direction)
        else:
            self.amount_controller.pause()

    def press(self, is_pressed):
        "Called when the user presses the button"
        if is_pressed:
            self.is_repeating = False
            self.timer.setInterval(self.threshold)
            self.timer.start()
        else:
            self.timer.stop()
            self.amount_controller.stop()

    def click(self):
        "Called when the user clicks the button"
        if self.is_repeating:
            pass
        elif self.click_cb:
            self.click_cb()

    def seek(self, amount):
        "Called to seek in the MPD server"
        status = self.client.status()
        if status.get('state','stopped') == 'play':
            song = int(status.get('song',0))
            time = int(status.get('time','0:0').split(':')[0]) + amount
            if (time < 0):
                song = song - 1
                if (song >= 0):
                    info = self.client.playlistinfo(song)[0]
                    time = time + int(info.get('time','0'))
                else:
                    return
            self.client.seek(song, time)


class SeekButton(Plasma.IconWidget):
    def __init__(self, parent, client, icon, direction, click):
        Plasma.IconWidget.__init__(self, icon, '', parent)
        self.setMaximumSize(24,24)
        self.client = client
        self.controller = SeekController(button=self,
                                         client=client,
                                         direction=direction,
                                         click=click)


class NextButton(SeekButton):
    def __init__(self, parent, client):
        SeekButton.__init__(self, 
                            parent, 
                            client, 
                            KIcon("media-skip-forward"), 
                            1,
                            Next(client))


class PrevButton(SeekButton):
    def __init__(self, parent, client):
        SeekButton.__init__(self,
                            parent,
                            client,
                            KIcon("media-skip-backward"), 
                            -1,
                            Prev(client))


class ActionButton(Plasma.IconWidget):
    def __init__(self, parent, icon, action):
        Plasma.IconWidget.__init__(self, icon, '', parent)
        self.connect(self, SIGNAL("clicked()"), action)
        self.setMaximumSize(24,24)

class PlayButton(ActionButton):
    PLAY_ICON = KIcon("media-playback-start")
    PAUSE_ICON = KIcon("media-playback-pause")

    def __init__(self, parent, client):

        ActionButton.__init__(self, parent, PlayButton.PLAY_ICON, PlayPause(client))
        self.client = client
        self.current_icon = PlayButton.PLAY_ICON
        self.connect(client, SIGNAL("status()"), self.update)
        self.update()

    def update(self):
        status = self.client.status()
        if status:
            state = status.get('state', 'stopped')
            new_icon = self.PAUSE_ICON if state == 'play' else self.PLAY_ICON
            if new_icon != self.current_icon:
                self.current_icon = new_icon
                self.setIcon(new_icon)

class StopButton(ActionButton):
    ICON = KIcon("media-playback-stop")

    def __init__(self, parent, client):
        ActionButton.__init__(self, parent, StopButton.ICON, Stop(client))



class VolumeSlider(Plasma.Slider):
    def __init__(self, parent, client):
        Plasma.Slider.__init__(self, parent)
        self.client = client
        self.setOrientation(Qt.Horizontal)
        self.setRange(0,100)
        self.connect(self, SIGNAL("valueChanged(int)"), SetVolume(client))
        self.connect(client, SIGNAL("status()"), self.update)
        self.update()

    def update(self):
        status = self.client.status()
        if status:
            volume = int(status.get('volume',-1))
            if volume >= 0 and volume != self.value():
                self.setValue(volume)


class PlaylistMoveUpButton(ActionButton):
    ICON = local_icon("playlist-up")

    def __init__(self, parent, client, playlist):
        ActionButton.__init__(self, parent, PlaylistMoveUpButton.ICON, PlaylistMoveUp(client, playlist))

class PlaylistMoveDownButton(ActionButton):
    ICON = local_icon("playlist-down")

    def __init__(self, parent, client, playlist):
        ActionButton.__init__(self, parent, PlaylistMoveDownButton.ICON, PlaylistMoveDown(client, playlist))

class PlaylistRandomizeButton(ActionButton):
    ICON = local_icon("playlist-random")

    def __init__(self, parent, client):
        ActionButton.__init__(self, parent, PlaylistRandomizeButton.ICON, PlaylistRandomize(client))

class PlaylistRemoveButton(ActionButton):
    ICON = local_icon("playlist-minus")

    def __init__(self, parent, client, selection):
        ActionButton.__init__(self, parent, PlaylistRemoveButton.ICON, PlaylistRemove(client, selection))

class PlaylistClearButton(ActionButton):
    ICON = local_icon("playlist-clear")
    def __init__(self, parent, client):
        ActionButton.__init__(self, parent, PlaylistClearButton.ICON, PlaylistClear(client))

class StatusButton(ActionButton):
    OK_ICON = KIcon("dialog-information")
    ERROR_ICON = KIcon("dialog-warning")

    def __init__(self, controller, client):
        ActionButton.__init__(self, controller.applet, StatusButton.OK_ICON, ToggleStatus(controller))
        self.client = client
        self.current_icon = StatusButton.OK_ICON
        self.connect(client, SIGNAL("status()"), self.update)
        self.update()

    def update(self):
        if self.client.status():
            new_icon = StatusButton.OK_ICON
        else:
            new_icon = StatusButton.ERROR_ICON

        if new_icon != self.current_icon:
            self.current_icon = new_icon
            self.setIcon(new_icon)

